/********************************************************************
 * File: uart.c
 * Description: AT89C52 serial communication program, the default
 * crystal oscillator frequency is 11.0592MHz.
 * Version: v0.0
 * Date: 2024-5-21
 * Author: zhengxinyu13@qq.com
 * ---------- Revision History ----------
 * <version> <date> <author> <desc>
 * 
 ********************************************************************/

#include "uart.h"

UART_REC uart_rec = {0};

/**
 * @brief Initialize the checksum, data bits, baud rate, and whether to
 *        open interrupts for the serial port.
 * @param baudrate (uint16_t) Set the baud rate value.
 * @param interrupt_enable (UART_IRP) UART interrupt switch,
 *        UART_IRP_ENABLE is turned on, and UART_IRP_DISABLE is turned off.
 * @param paritybit (PARITYBIT) Set the parity bit.
 */
void uart_init(uint16_t baudrate, UART_IRP irp_enable, PARITYBIT paritybit)
{
    if (paritybit == NONE_PARITY)
        SCON = 0x50;		// 8-bit variable UART.
    else if ((paritybit == ODD_PARITY) ||
            (paritybit == EVEN_PARITY) ||
            (paritybit == MARK_PARITY))
        SCON = 0xDA;		// 9-bit variable UART, parity bit initial to 1,
    else if (paritybit == SPACE_PARITY)
        SCON = 0xD2;		// 9-bit variable UART, parity bit initial to 0.

	TMOD &= 0x0F;
	TMOD |= 0x20;		// Set Timer1 as 8-bit auto reload mode.

	TH1 = -(FOSC/_12T_MODEL/SYSCLK/baudrate);	//Set auto-reload vaule.
    TL1 = TH1;
	TR1 = TURN_ON;		// Timer1 start run.

	if (irp_enable == UART_IRP_ENABLE) {
		ES  = TURN_ON;		// Enable UART interrupt.
		EA  = TURN_ON;		// Open master interrupt switch.
    } else if (irp_enable == UART_IRP_DISABLE) {
        ES  = TURN_OFF;		// Disable UART interrupt.
        EA  = TURN_OFF;		// Close master interrupt switch.
    }
}

/**
 * @brief Send a byte of data.
 * @param data_byte (uint8_t) data to be sent.
 */
void send_byte(uint8_t data_byte)
{
    SBUF = data_byte;	// Send data to UART buffer.
    while (!TI);
    RESET(TI);
}

/**
 * @brief Send a string of data.
 * @param data_string (uint8_t *) address of string.
 */
void send_string(uint8_t *data_string)
{
    while (*data_string)				// Check the end of the string.
        send_byte(*data_string++);		// Send current char and increment string ptr.
}

/**
 * @brief Print one character.
 * @param c (uint8_t) The characters that need to be printed.
 * @return uint8_t Return to the printf() function.
 */
int8_t putchar(int8_t c)
{
    send_byte(c);
    return c;
}

/**
 * @brief UART interrupt service routine.
 */
void uart_isr(void) interrupt 4
{
    uint8_t temp = 0;

    if (RI) {
        RESET(RI);	// Clear receive interrupt flag

        temp = SBUF;

        if (temp == 0 || temp == '\n' || uart_rec.len >= UART_BUF_SIZE ||
            temp == END_MARK) {
            uart_rec.buff[uart_rec.len] = '\0';
            uart_rec.flag = TURN_ON;
            uart_rec.len = 0;
        } else {
            uart_rec.buff[uart_rec.len++] = temp;
        }

        // if (uart_rec.flag) {
        //     send_string("Received successfully!\r\n");
        //     send_string(uart_rec.buff);
        //     send_string("\r\n");
        //     uart_rec.flag = TURN_OFF;
        // }
    }
}
